package com.ifast.asset.util;

import cn.hutool.core.net.NetUtil;
import org.apache.commons.lang3.StringUtils;
import org.lionsoul.ip2region.Util;

import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.net.InetAddress;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.text.Normalizer;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.net.UnknownHostException;

public class IpUtil {

    private final static String IPV4 = "^((2(5[0-5]|[0-4]\\d))|[0-1]?\\d{1,2})(\\.((2(5[0-5]|[0-4]\\d))|[0-1]?\\d{1,2})){3}$";
    private final static String IP_MASK = "^((128|192)|2(24|4[08]|5[245]))(\\.(0|(128|192)|2((24)|(4[08])|(5[245])))){3}$";

    //测试某个ip是否在一个网段中
    public static void main(String[] args) {

        //查询一个网段的  ip 开始   与结束
        //String start = getBeginIpStr("192.168.2.1","24");
        //String end = getEndIpStr("192.168.2.2","24");
        //System.out.println(start+" " +end);
        //System.out.println(isCrossIp(start,"192.168.2.1",end,"192.168.2.1"));

        List<String> list = getLocalAreaIpList("192.168.2.1", intToMask(24),true,true);
        for (int i = 0 ; i < list.size() ; i++){

            System.out.println(list.get(i));
        }

    }


    public static boolean getIsCrossIp(String ipPart, String ip) {

        try {
            if (ipPart.contains("/")) {
                String[] str = ipPart.split("/");

                String start = getBeginIpStr(str[0], str[1]);
                String end = getEndIpStr(str[0], str[1]);
                return isCrossIp(start, ip, end, ip);
            } else {
                return false;
            }
        } catch (Exception e) {

            e.printStackTrace();
        }
        return false;
    }

    /**
     * 获取请求用户的IP地址
     *
     * @return
     */
    public static String getRequestIp() {
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();
        return requestIp(request);
    }

    /**
     * 获取请求用户的IP地址
     *
     * @param request
     * @return
     */
    private static String requestIp(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }

        if ("0:0:0:0:0:0:0:1".equals(ip)) {
            ip = getLocalhostIp();
        }
        return ip;
    }

    /**
     * 获取本机的IP地址
     *
     * @return
     */
    public static String getLocalhostIp() {
        try {
            return NetUtil.getLocalhost().getHostAddress();
        } catch (Exception e) {
        }
        return null;
    }

    /**
     * 获得本机局域网 ip
     */
    public static String getLanIp() {
        return NetUtil.localIpv4s().stream()
                .filter(e -> e.startsWith("192"))
                .findFirst()
                .orElse(NetUtil.getLocalhost()
                        .getHostAddress()
                );
    }


    /**
     * 根据 ip/掩码位 计算IP段的起始IP 如 IP串 218.240.38.69/30
     *
     * @param ip      给定的IP，如218.240.38.69
     * @param maskBit 给定的掩码位，如30
     * @return 起始IP的字符串表示
     */
    public static String getBeginIpStr(String ip, String maskBit) {
        return getIpFromLong(getBeginIpLong(ip, maskBit));
    }

    /**
     * 根据 ip/掩码位 计算IP段的终止IP 如 IP串 218.240.38.69/30
     *
     * @param ip      给定的IP，如218.240.38.69
     * @param maskBit 给定的掩码位，如30
     * @return 终止IP的字符串表示
     */
    public static String getEndIpStr(String ip, String maskBit) {
        return getIpFromLong(getEndIpLong(ip, maskBit));
    }

    // 判断两个网段是否有交叉
    public static boolean isCrossIp(String startIp1, String startIp2, String endIp1, String endIp2) {

        // 将四个ip全部区分为数组
        // 判断规则 按照.分割 判断第一位是否相同 如果不同则判断起始2与结尾2是否在 起始1与结尾1之间 如果相同即判断下一位 依次判断第二位第三位第四位
        String[] startIps1 = startIp1.split("\\.");
        String[] startIps2 = startIp2.split("\\.");
        String[] endIps1 = endIp1.split("\\.");
        String[] endIps2 = endIp2.split("\\.");
        if (isCross(startIps1[0], startIps2[0], endIps1[0], endIps2[0])) {

            if (isCross(startIps1[1], startIps2[1], endIps1[1], endIps2[1])) {

                if (isCross(startIps1[2], startIps2[2], endIps1[2], endIps2[2])) {

                    if (isCross(startIps1[3], startIps2[3], endIps1[3], endIps2[3])) {

                        return true;
                    } else {
                        return false;
                    }
                } else {
                    return false;
                }
            } else {
                return false;
            }
        } else {
            return false;
        }

    }


    public static int calcNetMask(String startIp, String endIp) {
        return calcNetMask(Long.valueOf(Util.ip2long(startIp)).intValue(), Long.valueOf(Util.ip2long(endIp)).intValue());

    }

    public static int calcNetMask(int startIp, int endIp) {
        return Integer.bitCount(~startIp ^ endIp);
    }


    public static String getNetMask(String maskIndex) {
        StringBuilder mask = new StringBuilder();
        Integer inetMask = 0;
        try {
            inetMask = Integer.parseInt(maskIndex);
        } catch (NumberFormatException e) {
            System.out.println(e.getMessage());
            return null;
        }
        if (inetMask > 32) {
            return null;
        }
        // 子网掩码为1占了几个字节
        int num1 = inetMask / 8;
        // 子网掩码的补位位数
        int num2 = inetMask % 8;
        int array[] = new int[4];
        for (int i = 0; i < num1; i++) {
            array[i] = 255;
        }
        for (int i = num1; i < 4; i++) {
            array[i] = 0;
        }
        for (int i = 0; i < num2; num2--) {
            array[num1] += 1 << 8 - num2;
        }
        for (int i = 0; i < 4; i++) {
            if (i == 3) {
                mask.append(array[i]);
            } else {
                mask.append(array[i] + ".");
            }
        }
        return mask.toString();
    }

    public static Long getStartIp2Long(String segment) {
        return Util.ip2long(getStartIp(segment));
    }

    public static Long getEndIp2Long(String segment) {
        return Util.ip2long(getEndIp(segment));
    }


    public static String getStartIp(String segment) {
        if (segment == null) {
            return null;
        }
        String arr[] = segment.split("/");
        if (arr.length > 2) {
            return getBeginIpStr(arr[0], arr[1]);
        } else {
            return getBeginIpStr(arr[0], "32");
        }

    }

    /**
     * 根据网段计算结束IP
     *
     * @param segment
     * @return 结束IP
     */
    public static String getEndIp(String segment) {
        if (segment == null) {
            return null;
        }
        String arr[] = segment.split("/");
        if (arr.length > 2) {
            return getEndIpStr(arr[0], arr[1]);
        } else {
            return getEndIpStr(arr[0], "32");
        }
    }


    public static Long getBeginIpLong(String ip, String maskBit) {
        return getIpFromString(ip) & getIpFromString(getMaskByMaskBit(maskBit));
    }

    /**
     * 根据 ip/掩码位 计算IP段的终止IP 如 IP串 218.240.38.69/30
     *
     * @param ip      给定的IP，如218.240.38.69
     * @param maskBit 给定的掩码位，如30
     * @return 终止IP的长整型表示
     */
    public static Long getEndIpLong(String ip, String maskBit) {
        return getBeginIpLong(ip, maskBit) + ~getIpFromString(getMaskByMaskBit(maskBit));
    }

    public static String getIpFromLong(Long ip) {
        String s1 = String.valueOf((ip & 4278190080L) / 16777216L);
        String s2 = String.valueOf((ip & 16711680L) / 65536L);
        String s3 = String.valueOf((ip & 65280L) / 256L);
        String s4 = String.valueOf(ip & 255L);
        return s1 + "." + s2 + "." + s3 + "." + s4;
    }

    /**
     * 把xx.xx.xx.xx类型的转为long类型的
     *
     * @param ip
     * @return
     */
    public static Long getIpFromString(String ip) {
        Long ipLong = 0L;
        String ipTemp = ip;
        ipLong = ipLong * 256 + Long.parseLong(ipTemp.substring(0, ipTemp.indexOf('.')));
        ipTemp = ipTemp.substring(ipTemp.indexOf('.') + 1, ipTemp.length());
        ipLong = ipLong * 256 + Long.parseLong(ipTemp.substring(0, ipTemp.indexOf('.')));
        ipTemp = ipTemp.substring(ipTemp.indexOf(".") + 1, ipTemp.length());
        ipLong = ipLong * 256 + Long.parseLong(ipTemp.substring(0, ipTemp.indexOf('.')));
        ipTemp = ipTemp.substring(ipTemp.indexOf('.') + 1, ipTemp.length());
        ipLong = ipLong * 256 + Long.parseLong(ipTemp);
        return ipLong;
    }


    public static String getMaskByMaskBit(String maskBit) {
        return "".equals(maskBit) ? "error, maskBit is null !" : getMaskMap(maskBit);
    }

    public static String getMaskMap(String maskBit) {
        if ("0".equals(maskBit)) {
            return "0.0.0.0";
        }
        if ("1".equals(maskBit)) {
            return "128.0.0.0";
        }
        if ("2".equals(maskBit)) {
            return "192.0.0.0";
        }
        if ("3".equals(maskBit)) {
            return "224.0.0.0";
        }
        if ("4".equals(maskBit)) {
            return "240.0.0.0";
        }
        if ("5".equals(maskBit)) {
            return "248.0.0.0";
        }
        if ("6".equals(maskBit)) {
            return "252.0.0.0";
        }
        if ("7".equals(maskBit)) {
            return "254.0.0.0";
        }
        if ("8".equals(maskBit)) {
            return "255.0.0.0";
        }
        if ("9".equals(maskBit)) {
            return "255.128.0.0";
        }
        if ("10".equals(maskBit)) {
            return "255.192.0.0";
        }
        if ("11".equals(maskBit)) {
            return "255.224.0.0";
        }
        if ("12".equals(maskBit)) {
            return "255.240.0.0";
        }
        if ("13".equals(maskBit)) {
            return "255.248.0.0";
        }
        if ("14".equals(maskBit)) {
            return "255.252.0.0";
        }
        if ("15".equals(maskBit)) {
            return "255.254.0.0";
        }
        if ("16".equals(maskBit)) {
            return "255.255.0.0";
        }
        if ("17".equals(maskBit)) {
            return "255.255.128.0";
        }
        if ("18".equals(maskBit)) {
            return "255.255.192.0";
        }
        if ("19".equals(maskBit)) {
            return "255.255.224.0";
        }
        if ("20".equals(maskBit)) {
            return "255.255.240.0";
        }
        if ("21".equals(maskBit)) {
            return "255.255.248.0";
        }
        if ("22".equals(maskBit)) {
            return "255.255.252.0";
        }
        if ("23".equals(maskBit)) {
            return "255.255.254.0";
        }
        if ("24".equals(maskBit)) {
            return "255.255.255.0";
        }
        if ("25".equals(maskBit)) {
            return "255.255.255.128";
        }
        if ("26".equals(maskBit)) {
            return "255.255.255.192";
        }
        if ("27".equals(maskBit)) {
            return "255.255.255.224";
        }
        if ("28".equals(maskBit)) {
            return "255.255.255.240";
        }
        if ("29".equals(maskBit)) {
            return "255.255.255.248";
        }
        if ("30".equals(maskBit)) {
            return "255.255.255.252";
        }
        if ("31".equals(maskBit)) {
            return "255.255.255.254";
        }
        if ("32".equals(maskBit)) {
            return "255.255.255.255";
        }
        return "-1";
    }

    //判断两个范围是否有交集
    public static boolean isCross(String startIp1, String startIp2, String endIp1, String endIp2) {

        if ((Integer.valueOf(endIp1) < Integer.valueOf(startIp2)) || (Integer.valueOf(endIp2) < Integer.valueOf(startIp1))) {

            return false;
        }
        return true;
    }


    /**
     * 判断两个IP段是否存在冲突
     *
     * @param ipOne     ipOne
     * @param ipOneMask ipOne 掩码
     * @param ipTwo     ipTwo
     * @param ipTwoMask ipTwo 掩码
     * @return
     */
    public static boolean isIpRangeConflict(String ipOne, String ipOneMask, String ipTwo, String ipTwoMask) {
        String startIp = getBeginIpStr(ipOne, ipOneMask);
        String endIp = getEndIpStr(ipOne, ipOneMask);

        String startIp2 = getBeginIpStr(ipTwo, ipTwoMask);
        String endIp2 = getEndIpStr(ipTwo, ipTwoMask);
        if (isCrossIp(startIp, startIp2, endIp, endIp2)) {
            //证明有交集返回true
            return true;
        }
        return false;
    }

    /**
     * 判断主机地址能不能 ping 通，此处主机地址可以域名或者IP
     *
     * @param host
     * @return
     */
    public static boolean ping(String host) {
        if (Util.isIpAddress(host) || isDomain(host)) {
            return ping(host, 1, 700);
        }
        return false;
    }

    public static boolean ping(String ipAddress, int pingTimes, int timeOut) {
        BufferedReader in = null;
        Runtime r = Runtime.getRuntime();  // 将要执行的ping命令,此命令是windows格式的命令
        String pingCommand = "/usr/bin/ping " + ipAddress + " -c " + pingTimes + " -w " + timeOut;
        String pingCommand2 = "ping " + ipAddress + " -w " + timeOut;
        try {
            //System.out.println(pingCommand2);
            Process p = r.exec(pingCommand2);
            if (p == null) {
                return false;
            }
            in = new BufferedReader(new InputStreamReader(p.getInputStream()));   // 逐行检查输出,计算类似出现=23ms TTL=62字样的次数
            boolean connectedCount = false;
            String line = null;
            while ((line = in.readLine()) != null) {
                //System.out.println(line);
                connectedCount = getCheckResult(line);
                if (connectedCount) {
                    return true;
                }

            }   // 如果出现类似=23ms TTL=62这样的字样,出现的次数=测试次数则返回真
            return connectedCount;
        } catch (Exception ex) {
            ex.printStackTrace();   // 出现异常则返回假
            return false;
        } finally {
            try {
                in.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    //若line含有=18ms TTL=16字样,说明已经ping通,返回1,否則返回0.
    private static Boolean getCheckResult(String line) {
        //System.out.println("控制台输出的结果为:"+line);
        Pattern pattern = Pattern.compile("(ttl=\\d+)(\\s+)(\\d+ms)", Pattern.CASE_INSENSITIVE);
        if (line.contains("ttl=") || line.contains("TTL=")) {
            return true;
        }
        Matcher matcher = pattern.matcher(line);
        if (line.contains("ttl=64 time=")) {
            return true;
        }
        while (matcher.find()) {
            return true;
        }
        return false;
    }

    public static boolean checkIP(String str) {
        Pattern pattern = Pattern
                .compile("^((\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5]"
                        + "|[*])\\.){3}(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5]|[*])$");
        return pattern.matcher(str).matches();
    }

    public static boolean isValidIpv4Addr(String str) {
        String[] split = str.split("/");
        String regex = "^(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}$";
        if (split.length > 1) {
            int i = Integer.parseInt(split[1]);
            return split[0].matches(regex) && i > 0 && i <= 32;
        }
        return str.matches(regex);
    }


    public static String getIpByDomainName(String domainName) {
        try {
            return InetAddress.getByName(domainName).getHostAddress();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }

    public static boolean isHostReachable(String host, Integer timeOut) {
        try {
            //判断域名还是ip
            if (host.contains("www")) {
                host = getIpByDomainName(host);
            }
            return InetAddress.getByName(host).isReachable(timeOut);
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return false;
    }

    public static boolean isURL(String str) {
        //转换为小写
        str = str.toLowerCase();
        String regex = "^((https|http|ftp|rtsp|mms)?://)"  //https、http、ftp、rtsp、mms
                + "?(([0-9a-z_!~*'().&=+$%-]+: )?[0-9a-z_!~*'().&=+$%-]+@)?" //ftp的user@
                + "(([0-9]{1,3}\\.){3}[0-9]{1,3}" // IP形式的URL- 例如：199.194.52.184
                + "|" // 允许IP和DOMAIN（域名）
                + "([0-9a-z_!~*'()-]+\\.)*" // 域名- www.
                + "([0-9a-z][0-9a-z-]{0,61})?[0-9a-z]\\." // 二级域名
                + "[a-z]{2,6})" // first level domain- .com or .museum
                + "(:[0-9]{1,5})?" // 端口号最大为65535,5位数
                + "((/?)|" // a slash isn't required if there is no file name
                + "(/[0-9a-z_!~*'().;?:@&=+$,%#-]+)+/?)$";
        return str.matches(regex);
    }

    public static boolean isDomain(String domain) {
        domain = domain.toLowerCase();
        String regex = "^(?=^.{3,255}$)[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+$";
        return domain.matches(regex);
    }


    public static int getPrefixLengthByMack(String strip) {//输入子网掩码获得长度
        StringBuffer sbf;
        String str;
        // String strip = "255.255.255.0"; // 子网掩码
        int inetmask = 0, count = 0; // 子网掩码缩写代码
        String[] ipList = strip.split("\\.");
        for (int n = 0; n < ipList.length; n++) {
            sbf = toBin(Integer.parseInt(ipList[n]));
            str = sbf.reverse().toString();
            // 统计2进制字符串中1的个数
            count = 0;
            for (int i = 0; i < str.length(); i++) {
                i = str.indexOf('1', i); // 查找 字符'1'出现的位置
                if (i == -1) {
                    break;
                }
                count++; // 统计字符出现次数
            }
            inetmask += count;
        }
        return inetmask;
    }


    public static StringBuffer toBin(int x) {
        StringBuffer result = new StringBuffer();
        result.append(x % 2);
        x /= 2;
        while (x > 0) {
            result.append(x % 2);
            x /= 2;
        }
        return result;
    }


    public static boolean isValidIpv6Addr(String ipAddr) {

        String regex = "(^((([0-9A-Fa-f]{1,4}:){7}(([0-9A-Fa-f]{1,4}){1}|:))"
                + "|(([0-9A-Fa-f]{1,4}:){6}((:[0-9A-Fa-f]{1,4}){1}|"
                + "((22[0-3]|2[0-1][0-9]|[0-1][0-9][0-9]|"
                + "([0-9]){1,2})([.](25[0-5]|2[0-4][0-9]|"
                + "[0-1][0-9][0-9]|([0-9]){1,2})){3})|:))|"
                + "(([0-9A-Fa-f]{1,4}:){5}((:[0-9A-Fa-f]{1,4}){1,2}|"
                + ":((22[0-3]|2[0-1][0-9]|[0-1][0-9][0-9]|"
                + "([0-9]){1,2})([.](25[0-5]|2[0-4][0-9]|"
                + "[0-1][0-9][0-9]|([0-9]){1,2})){3})|:))|"
                + "(([0-9A-Fa-f]{1,4}:){4}((:[0-9A-Fa-f]{1,4}){1,3}"
                + "|:((22[0-3]|2[0-1][0-9]|[0-1][0-9][0-9]|"
                + "([0-9]){1,2})([.](25[0-5]|2[0-4][0-9]|[0-1][0-9][0-9]|"
                + "([0-9]){1,2})){3})|:))|(([0-9A-Fa-f]{1,4}:){3}((:[0-9A-Fa-f]{1,4}){1,4}|"
                + ":((22[0-3]|2[0-1][0-9]|[0-1][0-9][0-9]|"
                + "([0-9]){1,2})([.](25[0-5]|2[0-4][0-9]|"
                + "[0-1][0-9][0-9]|([0-9]){1,2})){3})|:))|"
                + "(([0-9A-Fa-f]{1,4}:){2}((:[0-9A-Fa-f]{1,4}){1,5}|"
                + ":((22[0-3]|2[0-1][0-9]|[0-1][0-9][0-9]|"
                + "([0-9]){1,2})([.](25[0-5]|2[0-4][0-9]|"
                + "[0-1][0-9][0-9]|([0-9]){1,2})){3})|:))"
                + "|(([0-9A-Fa-f]{1,4}:){1}((:[0-9A-Fa-f]{1,4}){1,6}"
                + "|:((22[0-3]|2[0-1][0-9]|[0-1][0-9][0-9]|"
                + "([0-9]){1,2})([.](25[0-5]|2[0-4][0-9]|"
                + "[0-1][0-9][0-9]|([0-9]){1,2})){3})|:))|"
                + "(:((:[0-9A-Fa-f]{1,4}){1,7}|(:[fF]{4}){0,1}:((22[0-3]|2[0-1][0-9]|"
                + "[0-1][0-9][0-9]|([0-9]){1,2})"
                + "([.](25[0-5]|2[0-4][0-9]|[0-1][0-9][0-9]|([0-9]){1,2})){3})|:)))$)";
        if (ipAddr == null) {
            System.out.println("ipv6 addresss is null ");
            return false;
        }
        ipAddr = Normalizer.normalize(ipAddr, Normalizer.Form.NFKC);
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(ipAddr);
        boolean match = matcher.matches();
        return match;
    }

    public static boolean isValidAddrWithMask(String addr) {
        if (StringUtils.isBlank(addr)) {
            return false;
        }
        if (!addr.contains("/")) {
            return false;
        }
        String[] addrArr = addr.split("\\/");
        String ip = addrArr[0];
        int mask = Integer.valueOf(addrArr[1]);
        //ipv4
        if (ip.contains(".")) {
            //校验mask
            if (mask < 0 || mask > 32) {
                return false;
            }
            //校验ip
            if (!isValidIpv4Addr(ip)) {
                return false;
            }
        } else if (ip.contains(":")) {
            //校验mask
            if (mask < 0 || mask > 128) {
                return false;
            }
            //校验ip
            if (!isValidIpv6Addr(ip)) {
                return false;
            }
        }
        return true;
    }

    public static List<String> getLocalAreaIpList(String ip, String mask, boolean containParamIp, boolean ignoreFirstAndLastIp) {
        if (!isIp(ip) || !isIpMask(mask)) return null;//非法ip或子网掩码
        String[] maskBinary = getIpBinary(mask);//子网掩码二进制数组
        //[11000000, 10101000, 00000000, 11111110]
        String[] ipBinary = getIpBinary(ip);//IP地址二进制数组
        //取同网段部分
        byte[] maskArr = toBinary(maskBinary);//二进制掩码数组
        byte[] ipArr = toBinary(ipBinary);//二进制IP数组
        int maskLen = 0;//子网掩码长度
        for (int i = 0; i < maskArr.length; i++) maskLen += maskArr[i];
//        int maskNumberLen = maskLen % 8;//子网位数,若为0 则8位全为主机号
//        System.out.println("子网号位数:" + maskNumberLen);
        int hostNumberLen = 32 - maskLen;//主机IP位数
//        System.out.println("主机号位数:" + hostNumberLen);
        int maxHost = 1 << hostNumberLen;
//        System.out.println("支持主机个数:" + maxHost);
        byte[] mod = new byte[32];//同网段二进制数组
        for (int i = 0; i < 32; i++) mod[i] = (byte) (maskArr[i] & ipArr[i]);
        List<String> ipList = new ArrayList<>(maxHost);
        StringBuilder genIp = new StringBuilder();//生成的IP
        for (int i = 0; i < maxHost; i++) {
            //转换为IP地址
            int decimal = 0;
            for (int j = 0; j < 32; j++) {
                decimal += mod[j] << (7 - j % 8);
                if (j != 0 && (j + 1) % 8 == 0) {
                    if (genIp.length() == 0) genIp.append(decimal);
                    else genIp.append(".").append(decimal);
                    decimal = 0;
                }
            }
            binaryArrayPlus(mod, 1);//从0开始增加maxHost次
//            System.out.println(genIp);//生成的IP
            String generateIp = genIp.toString();
            genIp.delete(0, genIp.length());//清空
            if (ignoreFirstAndLastIp && (i == 0 || i == maxHost - 1)) continue;//跳过首位地址
            if (!containParamIp && generateIp.equals(ip)) continue;//跳过相同地址
            ipList.add(generateIp);
        }
        return ipList;
    }

    public static boolean isIp(String ip) {
        if (ip == null) return false;
        Pattern patt = Pattern.compile(IPV4);
        return patt.matcher(ip).matches();
    }

    /**
     * 判断字符串是否为IPV4 子网掩码格式
     *
     * @param mask 要验证的子网掩码字符串
     * @return 是 true/ 否 false
     */
    public static boolean isIpMask(String mask) {
        if (mask == null) return false;
        Pattern patt = Pattern.compile(IP_MASK);
        return patt.matcher(mask).matches();
    }

    public static String [] getIpBinary(String ip){
        String[] strs = ip.split("\\.");
        for (int i = 0; i < 4; i++){
            strs[i] = Integer.toBinaryString(Integer.parseInt(strs[i]));
            if(strs[i].length() < 8) {
                StringBuilder zero = new StringBuilder();
                for (int j = 0; j < 8 - strs[i].length(); j++) zero.append("0");
                strs[i] = zero.toString() + strs[i];
            }
        }
        return strs;
    }
    public static byte[] toBinary(String[] binaryStrArr){
        int bl = binaryStrArr[0].length();
        byte[] bytes = new byte[bl * binaryStrArr.length];
        for(int i = 0; i < binaryStrArr.length; i++){
            for (int j = 0; j < bl; j++) bytes[i * bl + j] = (byte) (binaryStrArr[i].charAt(j) == '1' ? 1 : 0);
        }
        return bytes;
    }
    /**
     * 对二进制数组增加指定值
     * <p>如果增加的值超出此数组长度二进制最大表示值, 数组将重置为0, 从0开始增加</p>
     * @param binaryArray 二进制数组值应当全为1或0
     * @param plus 增加的数值10进制
     */
    public static void binaryArrayPlus(byte[] binaryArray, int plus){
        binaryArrayPlus(binaryArray, binaryArray.length - 1, plus);
    }

    /**
     * 对二进制数组增加指定值
     * <p>如果增加的值超出此数组长度二进制最大表示值, 数组将重置为0, 从0开始增加</p>
     * @param binaryArray 二进制数组值应当全为1或0
     * @param index 下标
     * @param plus 增加的数值10进制
     */
    private static void binaryArrayPlus(byte[] binaryArray, int index, int plus){
        if(index < 0) {
            binaryArray[0] = 0;
            return;
        }
        binaryArray[index] = (byte) (binaryArray[index] + 1);
        plus--;
        //如果进位,则递归进位
        if(binaryArray[index] > 1){
            binaryArrayPlus(binaryArray, index - 1, 1);
            binaryArray[index] = 0;
        }
        //如果增加的数超过1
        if(plus > 0) binaryArrayPlus(binaryArray, index, plus);
    }

    public static String intToMask(int bitMask){

        if(bitMask > 32){
            return null;
        }

        int tmpMask[] = {0,0,0,0};
        int times = bitMask / 8;
        int i = 0;
        for(; i < times ; i++)
        {
            tmpMask[i] = 255;
        }

        for(int j = 1; j <= 8; j++)
        {
            if(j <= bitMask - times*8)
                tmpMask[i] = 2*tmpMask[i] + 1;
            else
                tmpMask[i] = 2*tmpMask[i];
        }

       return Integer.toString(tmpMask[0]) + "." + Integer.toString(tmpMask[1]) +  "." +  Integer.toString(tmpMask[2])  + "." + Integer.toString(tmpMask[3]);

    }

}
